#ifndef __CM_NAT_WAN_P2P_CLIENT_H__
#define __CM_NAT_WAN_P2P_CLIENT_H__

#include "XMPPClient.h"
#include "IceLinkPool.h"
#include "JingleManager.h"
#include "MediaSession.h"
#include "eventhandler.h"

namespace cm_nat
{
    class WanP2PClient;

    class WanP2PClientListener
    {
    public:
        virtual void onReceive( WanP2PClient* p_wanP2P, ByteBuffer* data) =0;
        virtual void onState( WanP2PClient* p_wanP2P, int state ) =0;
    };

    class WanP2PClient: 
        public JingleManagerListener,
        public MediaSessionListener, 
        public IceLinkListener,
        public XMPPClientListener, 
        public EventHandler
    {
    public:
        WanP2PClient();
        ~WanP2PClient();

        void registerListener( WanP2PClientListener* p_listener );

        int setup(std::string username, std::string pwd, std::string server, UInt16 serverPort = 5222 );
        int teardown();

        //initiate a session
        int createSession();
        //exchange candidate
        int sendCandidate();
        
        //acknowledge the candidate to use 
        int selectCandidate();

        int send(ByteBuffer* data);

        int xmppPing();

        //from JingleManagerListener
        void onSessionInitiate(JingleSession* p_js);
        void onSessionTerminate(JingleSession* p_js);

        //from MediaSessionListener
        void onInitiate( MediaSession* p_session ); 
        void onAccept( MediaSession* p_session );
        void onCandidate( MediaSession* p_session, Candidate* cand );
        void onCheckResult( MediaSession* p_session, int result );
        void onSelectCandidate( MediaSession* p_session, Candidate* cand );

        //from IceLinkListener
        void onReceive(IceLink* link, ByteBuffer* data);
        void onLinkState( IceLink* link, int state );

        //XMPPClientListener
        void onConnect( XMPPClient* client );
        void onDisconnect( XMPPClient* client );

        //from EventHandler
        void handleEvent( const cm_xmpp::Event& event );

        enum LinkCheckResult{
            LINK_CHECK_NULL,
            LINK_CHECK_FAIL,
            LINK_CHECK_SUCCESS
        };

        enum PingResult{
            PING_NULL,
            PING_PONG,
            PING_ERROR
        };

    protected:
        std::string m_username;
        std::string m_resource;
        std::string m_password;
        std::string m_server;
        UInt16 m_serverPort;

        XMPPClient m_xmppClient;
        JingleManager m_jingleManager;

        MediaSession* m_mediaSessioin;

        IceLinkPool m_linkPool;
        
        IceLink* m_activeLink;
        IceLink* m_offerLink;
        IceLink* m_selectLink;

        LinkCheckResult m_activeLinkResult;
        LinkCheckResult m_peerLinkResult;

        WanP2PClientListener* m_listener;

        int m_pingResult;
    };
}

#endif